<?php
/**
 *  Copyright 2009 Michon van Dooren.
 *
 *  This file is part of DlScript.
 *
 *  DlScript is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  DlScript is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with DlScript.  If not, see <http://www.gnu.org/licenses/>.
 */
 
require_once('constants.php');

/** @file
 * This files contains all functions used by DlScript.
 */

/** @brief
 * Display a error message.
 *
 * Convenience function. Displays the error message using the error template, and stops the page loading.
 *
 * @param $msg
 *     The error message to be displayed.
 * @param $code
 *     The http status code to be given.
 */
function error($msg, $code = 404)
{
	global $template;
	
	$template->assign('error', $msg);
	
	// Send the headers and generated page.
	header("HTTP/1.0 $code {$http_headers[$code]}");
	$template->display('error.tpl');
	
	// Stop further loading of the page.
	die;
}

/** @brief
 * Download a file.
 *
 * Start the download of a file. Sends the right headers. Does not check for file permissions.
 *
 * @param $filename
 *     The file to download.
 */
function download($filename)
{
	// Send the headers
	header('Content-Type: ' . getmimetype($filename));
	header('Content-Disposition: attachment; filename=' . basename($filename));
	header('Content-Length: ' . filesize($filename));

	// Send the file thats requested.
	readfile($filename);
}

/** @brief
 * Get the extention of a file. 
 *
 * Uses the 'extentions' setting.
 *
 * @see $dlscript_settings
 *
 * @param $filename
 *     The filename to get the extention of.
 * 
 * @return
 *     The extention of the file, or NULL if this file has a invalid file extention.
 */
function getextention($filename)
{
	// Loop over the extentions.
	global $dlscript_settings;
	foreach ($dlscript_settings['extentions'] as $extention)
	{
		// Check if the extention of the file matches the extenxtion we're at in the loop.
		if (substr($filename, -1 * strlen($extention)) == $extention)
		{
			return $extention;
		}
	}
	
	return NULL;
}

/** @brief
 * Get the mime type of a file.
 *
 * Uses various methods, to ensure working on most versions of PHP.
 *
 * @param $filename
 *     The filename of which to get the mime type.
 *
 * @return
 *     The mime type of the file.
       Will default to 'application/octet-stream' if it cannot be determined in another way.
 */
function getmimetype($filename)
{
	// Get the mime type of the file.
	$type = 'application/octet-stream';
	if (function_exists('mime_content_type'))
	{
		$type = mime_content_type($filename);
	}
	elseif (class_exists('finfo'))
	{
		if (file_exists('magic'))
		{
			$finfo = new finfo(FILEINFO_MIME, 'magic');
		}
		else
		{
			$finfo = new finfo(FILEINFO_MIME);
		}
		$type = $finfo->file($filename);
	}
	return $type;
}

/** @brief
 * Get the base name of a file.
 * 
 * The base name is the filename, without the extention, and without paths and stuff attached.
 *
 * @see getextention
 * 
 * @param $filename
 *     The filename to get the base name of.
 *
 * @return
 *     The base name of the file.
 */
function getname($filename)
{
	return basename($filename, getextention($filename)); 
}

/** @brief
 * Get the requested path.
 *
 * This isn't always literally the patch that the user typed in, but some checks are made to test if the user has access to the requested location.
 *
 * @return
 *     If the user has requested a valid path, the path. If the path the has requested is invalid/unavailable for any reason, returns NULL.
 */
function getreqpath()
{
	// Get the path the user requested.
	$path = (isset($_GET['path'])) ? $_GET['path'] : getcwd();
	$path = realpath($path);

	// Check if the file being requested does exist.
	if (isset($_GET['path']) && !file_exists($_GET['path']))
	{
		return NULL;
	}

	// Check if it is a subdir of the directory dlscript is in, if not we will refuse access to the location.
	if (strncmp($path, realpath(getcwd()), strlen(realpath(getcwd()))))
	{
		return NULL;
	}
	
	// Check if the path is an absolute path - we will not allow this.
	if (substr($path, 0, 1) == '/')
	{
	    return NULL;
	}
	
	// Check if the path is hidden.
	if (is_hidden($path))
	{
		return NULL;
	}

	return $path;
}

/** @brief
 * Check if the path is hidden or not.
 *
 * Recursively checks if a certain path is hidden or not. Checks names starting with '.' and .hidden files. 
 *     Also checks the parent folders to see if they are visible or not.
 *
 * @param $path
 *     The path that is being tested for being hidden or not.
 *
 * @return
 *     True if $path is hidden (and thus not available), false if is is shown.
 */
function is_hidden($path)
{
	$looppath = $path;
		
	// Loop over the file/folder and its parents.
	while (realpath($looppath) != realpath(getcwd()))
	{
		// Check if the name start with a ".".
		if (substr(basename($looppath), 0, 1) == '.')
		{
			return true;
		}	
		
		// Check if it has a .hidden file.
		elseif (file_exists("$looppath/.hidden") || file_exists("$looppath.hidden"))
		{
			return true;
		}
		
		$looppath = realpath("$looppath/../");
	}
	
	// If the file is a directory, return false now to show that it is not hidden. 
	if (is_dir($path))
	{
		return false;
	}
	
	// Check if the file has a valid exention.
	return ((getextention($path)) == NULL);
}

/** @brief
 * Load the info of a download.
 *
 * Loads the .info file of a download. Creates the .info file with defaults if it doesn't exist yet.
 *
 * @see saveinfo
 * @see getname
 *
 * @param $name
 *     The base name of the download of which to get the info.
 * 
 * @return
 *     The file info.
 */
function loadinfo($name)
{
	if (!file_exists("$name.info"))
	{
		$info = array(
			'name' => getname($name),
			'count' => 0, 
			'iplist' => array(), 
			'downloads' => array()
		);
		saveinfo($name, $info);
		
		// Chmod the file so we can edit it later.
		chmod("$name.info", 0777);
	}
	
	return json_decode(file_get_contents("$name.info"), true);
}

/** @brief
 * Save the info of a download.
 *
 * Saves the .info file of a download.
 *
 * @see loadinfo
 * @see getname
 * 
 * @param $name
 *     The base name of the download of which to save the info.
 * @param $info
 *     The info to save to the .info file.
 */ 
function saveinfo($name, $info)
{
	file_put_contents("$name.info", json_encode($info));
}
